package com.ankang.controller;

import com.ankang.entity.ChannelLevel;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;

/**
 * 显示器控制器（基于ModbusTcpClient改造，用于显示通道烟叶等级）
 */
//@Slf4j
public class DisplayManager {


    private static final Logger log = LoggerFactory.getLogger(DisplayManager.class);

    private static final int CONNECT_TIMEOUT_MS = 3000; // 连接超时
    private static final int READ_TIMEOUT_MS = 3000; // 读取超时
    private static final String DEFAULT_ENCODING = "GB2312"; // 显示器编码（参考用户代码）
    private static final byte MODBUS_UNIT_ID = 0x01; // Modbus单元标识符
    private static final short MODBUS_START_ADDR = 0x0000; // Modbus起始地址

    // 显示器配置
    private final String displayIp;
    private final int displayPort;

    /**
     * 构造器（从ChannelLevel初始化显示器配置）
     * @param channelLevel 通道信息
     */
    public DisplayManager(ChannelLevel channelLevel) {
        this.displayIp = channelLevel.getDisplayIp();
        this.displayPort = channelLevel.getDisplayPort();
        Assert.hasText(displayIp, "显示器IP不能为空");
        Assert.isTrue(displayPort > 0, "显示器端口必须大于0");
    }

    /**
     * 发送烟叶等级到显示器（显示当前通道等级）
     * @param channelId 通道ID
     * @param targetGrade 目标等级
     */
    public void displayGrade(int channelId, String targetGrade) {
        Assert.notNull(targetGrade, "烟叶等级不能为空");
        String displayContent = targetGrade;
        log.info("显示器显示内容：{}", displayContent);

        try (Socket socket = new Socket()) {
            // 1. 连接显示器
            socket.connect(new java.net.InetSocketAddress(displayIp, displayPort), CONNECT_TIMEOUT_MS);
            socket.setSoTimeout(READ_TIMEOUT_MS);

            // 2. 编码显示内容（确保偶数字节，参考用户代码）
            Charset encoding = Charset.forName(DEFAULT_ENCODING);
            byte[] contentBytes = displayContent.getBytes(encoding);
            if (contentBytes.length % 2 != 0) {
                byte[] newBytes = new byte[contentBytes.length + 1];
                System.arraycopy(contentBytes, 0, newBytes, 0, contentBytes.length);
                contentBytes = newBytes; // 奇数字节补零
            }

            // 3. 构造Modbus请求（参考用户ModbusTcpClient.createModbusRequest）
            byte[] modbusRequest = createModbusRequest(contentBytes, MODBUS_START_ADDR, MODBUS_UNIT_ID);

            // 4. 发送请求并接收响应
            try (OutputStream os = socket.getOutputStream();
                 InputStream is = socket.getInputStream()) {
                os.write(modbusRequest);
                os.flush();

                // 读取响应（仅日志记录，无需业务处理）
                byte[] response = new byte[1024];
                int bytesRead = is.read(response);
                if (bytesRead > 0) {
                    log.info("显示器响应：{}", byteArrayToHexString(response, bytesRead));
                }
            }
            log.info("通道{} 显示器更新成功", channelId);

        } catch (SocketTimeoutException e) {
            log.error("通道{} 显示器超时：{}:{}", channelId, displayIp, displayPort, e);
        } catch (IOException e) {
            log.error("通道{} 显示器网络异常：{}:{}", channelId, displayIp, displayPort, e);
        } catch (Exception e) {
            log.error("通道{} 显示器调用异常：{}:{}", channelId, displayIp, displayPort, e);
        }
    }

    // ------------------------------ 私有辅助方法 ------------------------------
    /**
     * 构造Modbus TCP请求（参考用户ModbusTcpClient.createModbusRequest）
     */
    private byte[] createModbusRequest(byte[] data, short startAddress, byte unitId) {
        int dataLength = data.length;
        int requestLength = 23 + dataLength; // 固定头部23字节 + 数据负载
        byte[] request = new byte[requestLength];

        // MODBUS TCP Header（事务ID、协议ID、长度、单元ID）
        request[0] = 0x00; request[1] = 0x01; // 事务ID
        request[2] = 0x00; request[3] = 0x00; // 协议ID（Modbus）
        int pduLength = 16 + dataLength;
        int length = 1 + pduLength;
        request[4] = (byte) (length >> 8); request[5] = (byte) (length & 0xFF); // 长度
        request[6] = unitId; // 单元ID

        // MODBUS PDU（功能码16：写多个寄存器）
        request[7] = 0x10; // 功能码
        request[8] = (byte) (startAddress >> 8); request[9] = (byte) (startAddress & 0xFF); // 起始地址
        short registerCount = (short) (5 + dataLength / 2);
        request[10] = (byte) (registerCount >> 8); request[11] = (byte) (registerCount & 0xFF); // 寄存器数量
        request[12] = (byte) (10 + dataLength); // 字节计数

        // 控制参数（颜色：红，显示方式：左移，速度：6，停留时间：0）
        request[13] = 0x00; request[14] = 0x01; // 颜色（红）
//        request[15] = 0x00; request[16] = 0x01; // 显示方式（左移）
        request[15] = 0x00; request[16] = 0x03; // 显示方式：居中（值需参考显示器手册确认）
        request[17] = 0x00; request[18] = 0x06; // 速度（6）
        request[19] = 0x00; request[20] = 0x00; // 停留时间（0）
        request[21] = (byte) (dataLength >> 8); request[22] = (byte) (dataLength & 0xFF); // 内容长度

        // 数据负载
        System.arraycopy(data, 0, request, 23, dataLength);
        return request;
    }

    /**
     * 字节数组转十六进制字符串（辅助方法）
     */
    private String byteArrayToHexString(byte[] bytes, int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(String.format("%02X ", bytes[i] & 0xFF));
        }
        return sb.toString().trim();
    }

}
